""""""
"""
socket 介绍
socket (简称 套接字) 是进程之间通信的一个工具, 好比现实生活中的插座,所有的家电想要工作都是基于这个插座进行
进程之间想要进行网络通信需要 socket
socket 负责进程之间的网络数据传输, 好比数据的搬运工

我们目前大多数软件都是使用 socket 进行网络数据的传输
"""
"""
服务端和客户端
两个进程之间通过 socket 进行相互通讯,都必须有服务端和客户端

socket服务端: "等待"其他进程的连接, 可"接受"发来的信息, 可以"回复"信息
socket客户端: "主动"连接服务端, 可以"发送"消息, 可以"接收"回复

下面我们先介绍 socket服务端 的编程
"""
# 1. 创建 socket 对象

import socket  # 导包

socket_服务端 = socket.socket()  # 实际这里建立了一个类对象

"建立了对象,但是不能区分是客户端还是服务的,所以第2步就是定义成 服务端"
# 2. 绑定 对象 到指定的IP和地址(端口)
socket_服务端.bind(('127.0.0.1', 7777))  # 传参 IP和端口  (参数是一个元组,有2个元素)
# "localhost" 这里的主机名是代表 自己(本地主机) 的意思,或者 127.0.0.1

# 3. 服务端开始监听端口
socket_服务端.listen(2)
# __backlog 为int整数, 表示允许连接的数量. 超出会等待,可以不填, 不填会自动设置一个合理值

# 4. 接收客户端链接,获得连接对象
客户端_地址 = socket_服务端.accept()   # 特别说明返回值是给元组 第一个元素是个类对象 第二个元素是地址信息
conn客户端 = 客户端_地址[0]  # 客户端和服务端的连接对象 注意这个是类对象
地址 = 客户端_地址[1]   # 客户端的地址信息  这个是元组 2个元素
# 上面的写法也可以写成
# conn客户端, 地址 = socket_服务端.accept()

print(f'接收客户端连接,来自  {地址}')
"""
accept 方法是阻塞方法,如果没有连接,会卡在当前这一行,不向下执行代码
accept 返回的是一个元组有2给元素. 可以使用上述形式,用两个变量接收元组的两个元素
"""

# 5. 客户端连接后,通过 recv 方法,接收客户端发送的消息 (只要这里要使用 客户端和服务端的连接对象)
while True:
    接收数据 = conn客户端.recv(1024)  # 缓冲区
    字符串 = 接收数据.decode("UTF-8")  # 解码
    # recv 方法的返回值是字节数组(Bytes), 可以通过 decode 使用UTF-8编码转换为字符串
    # recv 方法的传参是 buffsize 缓冲区大小. 一般设置为1024即可
    print("接收客户端发来的数据:", 字符串)

    # 可以通过无限循环, 来持续和客户端进行数据交互
    # 可以通过判定客户端发来的特殊标记,比如 "exit" 来退出无限循环 (通用惯例)
    if 字符串 == "exit":
        break  # 满足条件退出无限循环

    # 6. 同时可以回复客户端消息
    发送给客户端信息 = input("输入你要给客户端发送的信息:")
    字节数组 = 发送给客户端信息.encode("UTF-8")  # 注意这里是编码操作 是把字符串转换成 字节数组(Bytes)
    conn客户端.send(字节数组)
    if 发送给客户端信息 == "exit":  # 满足条件退出循环
        break

# 6. 通过 conn (客户端当次连接对象),调用send方法可以回复消息
"""
while True:
    接收数据 = conn客户端.recv(1024).decode("UTF-8")  # 注意这里是编码操作
    if 接收数据 == "exit":
        break  # 满足条件退出无限循环
    print("接收到发来的数据:", 接收数据)
    conn客户端.send("欢迎访问".encode("UTF-8"))  # 可以向客户端发送信息 这里是编码操作
"""

# 7. 关闭 conn (客户端当次连接对象)和服务端对象,关闭连接
conn客户端.close()
socket_服务端.close()
